package com.weixing.mall.provider.util;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class App
{
	/**
	 * 加密算法,CBC模式
	 */
	private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
 
	/**
	 * 用于生成随机iv
	 * 
	 * @param length
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	private static byte[] getSecureRandom(int length) throws NoSuchAlgorithmException
	{
		byte[] randomByte = new byte[length];
 
		SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
		secureRandom.nextBytes(randomByte);
 
		return randomByte;
	}
 
	/**
	 * 不同长度的种子seed,生成一样长度的key
	 * 
	 * @param seed
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	private static byte[] getSecretKey(byte[] seed) throws NoSuchAlgorithmException
	{
		KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
		SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
 
		secureRandom.setSeed(seed);
		keyGenerator.init(256, secureRandom); // 256 bits or 128 bits,192bits
		SecretKey secretKey = keyGenerator.generateKey();
		byte[] result = secretKey.getEncoded();
 
		return result;
	}
 
	private static byte[] aesCipher(byte[] source, byte[] key, byte[] iv, int mode)
			throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
			InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
		IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
 
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(mode, secretKeySpec, ivParameterSpec);
 
		return cipher.doFinal(source);
	}
 
	private static String encrypt(String source, String key) throws Exception
	{
		try
		{
			byte[] iv = getSecureRandom(16);
 
			byte[] resultByte = aesCipher(source.getBytes(StandardCharsets.UTF_8), getSecretKey(key.getBytes()), iv,
					Cipher.ENCRYPT_MODE);
 
			Base64.Encoder encoder = Base64.getEncoder();
			String encodeToString = encoder.encodeToString(resultByte);
			System.out.println(encodeToString);
			// iv值拼接在密文值后面
			return encodeToString.concat(new String(Hex.encodeHex(iv)));
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (InvalidKeyException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (NoSuchPaddingException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (InvalidAlgorithmParameterException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (IllegalBlockSizeException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (BadPaddingException e)
		{
			throw new Exception(e.getMessage());
		}
	}
 
	private static String decrypt(String source, String key) throws Exception
	{
		try
		{
			// 先分别解析密文值和iv值
			String message = source.substring(0, source.length() - 32);
			String iv = source.substring(source.length() - 32, source.length());
 
			Base64.Decoder decoder = Base64.getDecoder();
 
			byte[] resultByte = aesCipher(decoder.decode(message), getSecretKey(key.getBytes()),
					Hex.decodeHex(iv.toCharArray()), Cipher.DECRYPT_MODE);
 
			return new String(resultByte, StandardCharsets.UTF_8);
		}
		catch (InvalidKeyException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (NoSuchPaddingException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (InvalidAlgorithmParameterException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (IllegalBlockSizeException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (BadPaddingException e)
		{
			throw new Exception(e.getMessage());
		}
		catch (DecoderException e)
		{
			throw new Exception(e.getMessage());
		}
	}
 
	public static void main(String[] args)
	{
		// key长度随意
		String key = "1dc5d72e5b3a097cca875cce84c402946";
		String source = "RealJt";
 
		String encryptResult = null;
		String encryptResult1 = null;
		try
		{
			encryptResult = encrypt(source, key);
			encryptResult1 = encrypt(source, key);
			System.out.println(encryptResult);
			System.out.println(encryptResult1);
		}
		catch (Exception e)
		{
			System.out.println("encrypt error.");
		}
 
		try
		{
			System.out.println(decrypt(encryptResult, key));
			System.out.println(decrypt(encryptResult1, key));
		}
		catch (Exception e)
		{
			System.out.println("decrypt error.");
		}
	}
 
}